package form.ui.core {
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.geom.Point;
	import flash.utils.Timer;
	
	import form.core.StyleManager;
	import form.core.TooltipManager;
	import form.events.StyleEvent;
	import form.utils.MathUtils;

	public class FMSprite extends Sprite 
	{		
	    public static const DEFAULT_MEASURED_WIDTH:Number = 160;	
	    public static const DEFAULT_MEASURED_MIN_WIDTH:Number = 40;	
	    public static const DEFAULT_MEASURED_HEIGHT:Number = 22;	
	    public static const DEFAULT_MEASURED_MIN_HEIGHT:Number = 22;	
	    public static const DEFAULT_MAX_WIDTH:Number = 10000;
	    public static const DEFAULT_MAX_HEIGHT:Number = 10000;
		
		private static const DEFAULT_WIDTH:int = 0;
		private static const DEFAULT_HEIGHT:int = 0;
		
		private static const DEFAULT_FILL_COLOR:int = 0xffffff;
		private static const DEFAULT_FILL_OPACITY:Number = 0;
		
		private static const DEFAULT_STROKE_THICKNESS:int = 0;
		private static const DEFAULT_STROKE_COLOR:int = 0x000000;
		private static const DEFAULT_STROKE_OPACITY:Number = 0;
		
		protected var styleManager:StyleManager = StyleManager.getInstance();
		private var toolTipTimer:Timer;
		
		public function FMSprite() 
		{
			this.fillColor = FMSprite.DEFAULT_FILL_COLOR;
			this.fillOpacity = FMSprite.DEFAULT_FILL_OPACITY;
			
			this.strokeThickness = FMSprite.DEFAULT_STROKE_THICKNESS;
			this.strokeColor = FMSprite.DEFAULT_STROKE_COLOR;
			this.strokeOpacity = FMSprite.DEFAULT_STROKE_OPACITY;
			
			this.dimensions = [FMSprite.DEFAULT_WIDTH, FMSprite.DEFAULT_HEIGHT];
			
			this.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage, false, 0, true); 
						
			styleManager.addEventListener(StyleEvent.STYLE_COMPLETE, onUpdateStyle, false, 0, true);
			styleManager.addEventListener(StyleEvent.STYLE_GLOBAL, onGlobalStyleSetting, false, 0, true);
			
			toolTipTimer = new Timer(TooltipManager.DELAY, 1);
			toolTipTimer.addEventListener(TimerEvent.TIMER, resetToolTip, false, 0, true);
		}
		
		//------------------------------------------------------
		//
		// Properties
		//
		//------------------------------------------------------
		
		//------------------------------------------
		//
		// toolTip
		//
		//------------------------------------------
		
		private var _toolTip:String;
		public function get toolTip():String
		{
			return _toolTip;
		}
		public function set toolTip(value:String):void
		{
			if(value && _toolTip != value)
			{
				if(!_toolTip)
				{
					this.addEventListener(MouseEvent.ROLL_OVER, onShowToolTip, false, 0 , true);
				}
					
				_toolTip = value;
			}
		}
		
		//------------------------------------------
		//
		// fillColor
		//
		//------------------------------------------
		
		private var _fillColor:int;
		public function set fillColor(value:int):void 
		{
			if (value != this.fillColor) 
			{
				this._fillColor = value;
				this.draw();
			}
		}		
		public function get fillColor():int 
		{ 
			return this._fillColor;
		}
		
		public function get backgroundColor():uint
		{
			return fillColor;
		}
		
		public function set backgroundColor(value:uint):void
		{
			fillColor = value;
			fillOpacity = 1;
		}
		
		//------------------------------------------
		//
		// fillOpacity
		//
		//------------------------------------------
		
		private var _fillOpacity:Number;
		public function set fillOpacity(value:Number):void 
		{
			if (value != this.fillOpacity) 
			{
				this._fillOpacity = value;
				this.draw();
			}
		}		
		public function get fillOpacity():Number 
		{ 
			return this._fillOpacity;
		}
		
		//------------------------------------------
		//
		// strokeThickness
		//
		//------------------------------------------
		
		private var _strokeThickness:Number;
		public function set strokeThickness(value:Number):void 
		{
			if (value != this.strokeThickness) 
			{
				this._strokeThickness = value;
				this.draw();
			}
		}		
		public function get strokeThickness():Number 
		{ 
			return this._strokeThickness;
		}
		
		//------------------------------------------
		//
		// strokeColor
		//
		//------------------------------------------
		
		private var _strokeColor:int;
		public function set strokeColor(value:int):void 
		{
			if (value != this.strokeColor) 
			{
				this._strokeColor = value;
				this.draw();
			}
		}		
		public function get strokeColor():int 
		{ 
			return this._strokeColor;
		}
		
		//------------------------------------------
		//
		// strokeOpacity
		//
		//------------------------------------------
				
		private var _strokeOpacity:Number;
		public function set strokeOpacity(value:Number):void 
		{
			if (value != this.strokeOpacity) 
			{
				this._strokeOpacity = value;
				this.draw();
			}
		}		
		public function get strokeOpacity():Number 
		{ 
			return this._strokeOpacity;
		}
		
		//------------------------------------------
		//
		// strokeCorner
		//
		//------------------------------------------
		
		private var _strokeCorner:Number;
		public function set strokeCorner(value:Number):void 
		{
			if (value != this.strokeCorner) 
			{
				this._strokeCorner = value;
				this.draw();
			}
		}		
		public function get strokeCorner():Number 
		{ 
			return this._strokeCorner;
		}
		
		//------------------------------------------
		//
		// coordinates
		//
		//------------------------------------------
		
		public function set coordinates(array:Array):void 
		{
			this.x = array[0];
			this.y = array[1];
		}		
		public function get coordinates():Array 
		{
			return [this.x, this.y];	
		}
		
		//------------------------------------------
		//
		// width
		//
		//------------------------------------------
		
		private var _width:Number;		
		public override function set width(value:Number):void 
		{ 
			if (value != this.width) 
			{
				this._width = value; 
				this.draw();
			}
		}		
		public override function get width():Number { return this._width; }
		
		//------------------------------------------
		//
		// height
		//
		//------------------------------------------
		
		private var _height:Number;
		public override function set height(value:Number):void 
		{ 
			if (value != this.height) 
			{
				this._height = value; 
				this.draw();
			}
		}		
		public override function get height():Number { return this._height; }
			
		
		//------------------------------------------
		//
		// percentWidth
		//
		//------------------------------------------
		
		private var _percentWidth:Number;	
		public function get percentWidth():Number{return _percentWidth}
		public function set percentWidth(value:Number):void{_percentWidth = value}
		
		//------------------------------------------
		//
		// percentHeight
		//
		//------------------------------------------
		
		private var _percentHeight:Number;
		public function get percentHeight():Number{return _percentHeight}
		public function set percentHeight(value:Number):void{_percentHeight = value}
		
		//------------------------------------------
		//
		// minWidth
		//
		//------------------------------------------
		
		private var _minWidth:Number;
		public function get minWidth():Number{return _minWidth}
		public function set minWidth(value:Number):void{_minWidth = value}
		
		//------------------------------------------
		//
		// minHeight
		//
		//------------------------------------------
		
		private var _minHeight:Number;
		public function get minHeight():Number{return _minHeight}
		public function set minHeight(value:Number):void{_minHeight = value}
				
		//------------------------------------------
		//
		// paddingTop
		//
		//------------------------------------------
		
		private var _paddingTop:Number = 0;		
		public function get paddingTop():Number{return _paddingTop}
		public function set paddingTop(value:Number):void{_paddingTop = value}
		
		//------------------------------------------
		//
		// paddingRight
		//
		//------------------------------------------
		
		private var _paddingRight:Number = 0;
		public function get paddingRight():Number{return _paddingRight}
		public function set paddingRight(value:Number):void{_paddingRight = value}
		
		//------------------------------------------
		//
		// paddingBottom
		//
		//------------------------------------------
		
		private var _paddingBottom:Number = 0;
		public function get paddingBottom():Number{return _paddingBottom}
		public function set paddingBottom(value:Number):void{_paddingBottom = value}
		
		//------------------------------------------
		//
		// paddingLeft
		//
		//------------------------------------------
		
		private var _paddingLeft:Number = 0;
		public function get paddingLeft():Number{return _paddingBottom}
		public function set paddingLeft(value:Number):void{_paddingBottom = value}
		
		//------------------------------------------
		//
		// dimensions
		//
		//------------------------------------------
		
		public function set dimensions(array:Array):void 
		{
			var width:int = array[0];
			var height:int = array[1];
			var change:Boolean = false;
			
			if (width != this.width) 
			{ 
				this._width = width; 
				change = true;
			}
			if (height != this.height) 
			{ 
				this._height = height; 
				change = true;
			}
			
			if (change) this.draw(); 
		}		
		public function get dimensions():Array 
		{
			return [this.width, this.height];
		}
		
		//------------------------------------------
		//
		// styleDelcare
		//
		//------------------------------------------
		
		private var _styleDelcare:Object = 
			{'percentWidth':NaN,
			 'percentHeight':NaN,
			 'paddingTop':NaN,
			 'paddingRight':NaN,
			 'paddingBottom':NaN,
			 'paddingLeft':NaN,
			 'width':NaN,
			 'height':NaN,
			 'backgroundColor': NaN
			};
		public function get styleDelcare():Object
		{
			return _styleDelcare;
		}
		public function set styleDelcare(value:Object):void
		{
			_styleDelcare = value;
		}
		
		//------------------------------------------------------
		//
		// methods
		//
		//------------------------------------------------------
		
		
		public function draw():void 
		{
			if (this.stage == null || !this.width || !this.height) { return; }
			
			this.graphics.clear();
			this.graphics.beginFill(this.fillColor, this.fillOpacity);
			if (this.strokeThickness && this.strokeOpacity) 
			{
				this.graphics.lineStyle(this.strokeThickness, this.strokeColor, this.strokeOpacity);
			}
			if(_strokeCorner)
			{
				this.graphics.drawRoundRect(0, 0, this.width, this.height, this.strokeCorner, this.strokeCorner);
			}
			else
				this.graphics.drawRect(0, 0, this.width, this.height);
			this.graphics.endFill();
		}
		
		private function onAddedToStage(e:Event):void 
		{
			this.draw();
			this.stage.addEventListener(MouseEvent.MOUSE_OUT, hideToolTip, false, 0, true);
		}
				
		//------------------------------------------
		//
		// style releated methods
		//
		//------------------------------------------
		
		public function registerStyle(name:String, value:Object = null):void
		{
			_styleDelcare[name] = value;
			if(MathUtils.isValid(_styleDelcare[name]))
			{
				this[name] = _styleDelcare[name];
			}
		}
		public function removeStyle(name:String):void
		{
			if(name in _styleDelcare) delete _styleDelcare[name];
		}
		public function hasRegistedStyle(name:String):Boolean
		{
			return name in _styleDelcare;
		}
		
		
		protected function onUpdateStyle(e:StyleEvent):void
		{
			if(e.updateNow)
			{
				updateStyle();
			}
		}
		
		protected function onGlobalStyleSetting(e:StyleEvent):void
		{
			//
		}
		
		public function updateStyle():void
		{
			for(var p:String in styleDelcare)
			{
				if(MathUtils.isValid(styleDelcare[p]))this[p] = styleDelcare[p]	
			}
		}
		
		//------------------------------------------
		//
		// tool-tip releated methods
		//
		//------------------------------------------
		
		private var toolTipDisplayed:Boolean;		
		private function onShowToolTip(e:MouseEvent):void
		{
			if(!toolTipDisplayed)
			{
				toolTipDisplayed = true;
				showToolTip();				
			}
		}
		
		public function showToolTip():void
		{
			var point:Point = localToGlobal(new Point(mouseX, mouseY));
			TooltipManager.getInstance().showToolTip(this, point.x, point.y);
			toolTipTimer.stop();
			toolTipTimer.reset();
			toolTipTimer.start();
		}
		 
		private function resetToolTip(e:Event = null):void
		{
			toolTipDisplayed = false;			
		}
		
		private function hideToolTip(e:MouseEvent):void
		{
			TooltipManager.getInstance().removeToolTip();
		}
	}
}